﻿using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using System;
using System.Windows.Media;
using System.Collections.Generic;
using System.Windows;
using System.Linq;

namespace NFox.Pyeditor.Runtime
{
    public class Marker : TextSegment, IBackgroundRenderer
    {

        public Marker() { }

        public Marker(int start, int length)
        {
            StartOffset = start;
            Length = length;
        }

        public KnownLayer Layer
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public virtual void Draw(TextView textView, DrawingContext drawingContext)
        {
            
        }
    }

    public class TextMarker : Marker
    {

        public TextMarker() { }

        public TextMarker(int start, int length) : base(start, length) { }

        public Brush BackgroundBrush { get; set; } = Brushes.Transparent;

        public Color? BorderColor { get; set; }

        public Color MarkerColor { get; set; }
        public string ToolTip { get; set; }

        public override void Draw(TextView textView, DrawingContext drawingContext)
        {
            base.Draw(textView, drawingContext);
            var geoBuilder = new BackgroundGeometryBuilder { AlignToWholePixels = true, CornerRadius = 3 };
            geoBuilder.AddSegment(textView, this);
            Geometry geometry = geoBuilder.CreateGeometry();
            if (geometry != null && BackgroundBrush != Brushes.Transparent && BorderColor != null)
            {
                Pen pen = null;
                if (BorderColor != null)
                    pen = new Pen(new SolidColorBrush(BorderColor.Value), 1);
                BackgroundBrush.Freeze();
                drawingContext.DrawGeometry(BackgroundBrush, pen, geometry);
            }
        }

    }

    public class ErrorMarker : TextMarker, IEquatable<ErrorMarker>
    {

        public ErrorMarker(TextDocument doc, dynamic e)
        {
            StartOffset = doc.Lines[e.Line - 1].Offset + e.Column - 1;
            Length = e.RawSpan.Length;
            ToolTip = e.Message;
            MarkerColor = Colors.Red;
        }

        public bool Equals(ErrorMarker other)
        {
            return
                other != null &&
                StartOffset == other.StartOffset &&
                Length == other.Length &&
                ToolTip == other.ToolTip;
        }

        public override void Draw(TextView textView, DrawingContext drawingContext)
        {
            base.Draw(textView, drawingContext);
            foreach (Rect r in BackgroundGeometryBuilder.GetRectsForSegment(textView, this))
            {
                Point startPoint = r.BottomLeft;
                Point endPoint = r.BottomRight;

                var usedPen = new Pen(new SolidColorBrush(MarkerColor), 1);
                usedPen.Freeze();
                const double offset = 2.5;

                int count = Math.Max((int)((endPoint.X - startPoint.X) / offset) + 1, 4);

                var geometry = new StreamGeometry();

                using (StreamGeometryContext ctx = geometry.Open())
                {
                    ctx.BeginFigure(startPoint, false, false);
                    ctx.PolyLineTo(CreatePoints(startPoint, endPoint, offset, count).ToArray(), true, false);
                }

                geometry.Freeze();

                drawingContext.DrawGeometry(Brushes.Transparent, usedPen, geometry);
                break;
            }
        }

        private IEnumerable<Point> CreatePoints(Point start, Point end, double offset, int count)
        {
            for (int i = 0; i < count; i++)
            {
                yield return new Point(start.X + (i * offset), start.Y - ((i + 1) % 2 == 0 ? offset : 0));
            }
        }

    }

}
